function s=parseoutputfiles(s,outputFiles,docFile)
%PARSEOUTPUTFILES Parse output files section of a DBAT XML file.
%
%    S=PARSEOUTPUTFILES(FILES,DOCFILE,S) parses the output/files XML
%    block FILES from a DBAT XML script file and generates the
%    requested files. The string DOCFILE should contain the path name
%    of the XML file and is used to determine base directories.
%
%See also: PARSEINPUT.

narginchk(3,3);

knownFields={'Attributes','report','io','eo','image_residuals','c'};
[ok,msg]=checkxmlfields(outputFiles,knownFields,false(size(knownFields)));
if ~ok, error('DBAT XML script output/files error: %s',msg); end

% Check if a base directory was specified.
[baseDir,rawBaseDir]=getattrbasedir(outputFiles,docFile);

% Warn if base dir does not exist.
if ~isempty(baseDir) && ~exist(baseDir,'dir')
    warning('DBAT output base directory %s (%s) does not exist!',baseDir, ...
            rawBaseDir);
end

files=fieldnames(outputFiles);

for i=1:length(files)
    file=files{i};
    switch file
      case 'Attributes'
        % Do nothing
      case 'report'
        WriteReportFile(s,outputFiles.report,baseDir);
      case 'io'
        WritePostIOFile(s,outputFiles.io,baseDir);
      case 'eo'
        WritePostEOFile(s,outputFiles.eo,baseDir,docFile);
      case 'image_residuals'
        WriteImageResidualsFile(s,outputFiles.image_residuals,baseDir,docFile);
      case 'c'
        % Do nothing
      otherwise
        error('DBAT XML script output/file error: Unknown file %s',file);
    end
end


function WriteReportFile(s,report,baseDir)
% Write a report file.

[ok,msg]=checkxmlfields(report,'file');
if ~ok, error('DBAT XML script output/files/report error: %s',msg); end

file=report.file;

% File name should be in the 'Text' field.
[ok,msg]=checkxmlfields(file,'Text');
if ~ok, error('DBAT XML script output/files/report/file error: %s',msg); end

% Get filename.
fileName=parsepath(file.Text,baseDir);

% Verify that directory exists.
if ~exist(fileparts(fileName),'dir')
    error('DBAT XML error: Output dir %s does not exist',fileparts(fileName));
end

s.bundle.info=bundle_cov(s,s.bundle.info,'prepare');

fprintf('\nBundle result file %s generated.\n',fileName);
s=bundle_result_file(s,s.bundle.info,fileName);


function WriteImageResidualsFile(s,imageResiduals,baseDir,docFile)
% Write a file with the largest image residuals.

[ok,msg]=checkxmlfields(imageResiduals,{'file','Attributes'},[true,false]);
if ~ok, error('DBAT XML script output/files/image_residuals error: %s',msg); end

if isfield(imageResiduals,'Attributes') && ...
        isfield(imageResiduals.Attributes,'top_count')
    topCount=sscanf(imageResiduals.Attributes.top_count,'%d');
else
    topCount=1000;
end

file=imageResiduals.file;

% File name should be in the 'Text' field.
[ok,msg]=checkxmlfields(file,'Text');
if ~ok, error('DBAT XML script output/files/report/file error: %s',msg); end

% Get filename.
fileName=parsepath(file.Text,baseDir);

% Verify that directory exists.
if ~exist(fileparts(fileName),'dir')
    error('DBAT XML error: Output dir %s does not exist',fileparts(fileName));
end

[fid,msg]=fopen(fileName,'wt+');
if fid<0
    error('Cannot open file %s for writing: %s',fileName,msg);
end

fprintf(fid,'# Top residual listing for dbat script file\n# %s.\n', ...
        docFile);
[v,d]=dbatversion;
fprintf(fid,'# Generated by DBAT version %s (%s).\n',v,d);
fprintf(fid,'# Execution UUID: %s.\n',s.proj.UUID);
fprintf(fid,'# Listing top %d residuals.\n',topCount);
fprintf(fid,'# Format: OP id, image id, x, y, resx, resy, resTot\n');

resVec=s.post.res.IP;
resNorm=sqrt(sum(resVec.^2,1));
[topNorm,i]=sort(resNorm,'descend');

if length(topNorm)>topCount
    topNorm=topNorm(1:topCount);
    i=i(1:topCount);
end

for ii=1:length(i)
    [OPix,imIx]=find(s.IP.ix==i(ii));
    % Measured coordinates.
    xy=s.IP.val(:,i(ii));
    res=s.post.res.IP(:,i(ii));
    OPid=s.OP.id(OPix);
    imId=s.EO.id(imIx);
    fprintf(fid,'%d, %d, %g, %g, %g, %g, %g\n',OPid,imId,xy,res,norm(res));
end

fclose(fid);

fprintf('Top residual file %s generated.\n',fileName);

function WritePostIOFile(s,io,baseDir)
% Write a DBAT camera XML file.

[ok,msg]=checkxmlfields(io,'file');
if ~ok, error('DBAT XML script output/files/io error: %s',msg); end

file=io.file;

% File name should be in the 'Text' field.
[ok,msg]=checkxmlfields(file,'Text');
if ~ok, error('DBAT XML script output/files/io/file error: %s',msg); end

% Get filename.
fileName=parsepath(file.Text,baseDir);

% Verify that directory exists.
if ~exist(fileparts(fileName),'dir')
    error('DBAT XML error: Output dir %s does not exist',fileparts(fileName));
end

% Get a single-camera XML struct for camera 1.
if isfield(s.post,'cams')
    cam=XMLStruct(s.post.cams{1});
    xml=struct('document',struct('Attributes', ...
                                 struct('dbat_camera_version','1.0'),...
                                 'cameras',cam));
    struct2xml(xml,fileName);
    fprintf('IO result file %s generated.\n',fileName);
else
    warning(['No posterior camera present. Bundle may have failed. ' ...
             'Not writing IO file.']);
end

function WritePostEOFile(s,eo,baseDir,docFile)
% Write a file with the largest image residuals.

[ok,msg]=checkxmlfields(eo,'file');
if ~ok, error('DBAT XML script output/files/eo error: %s',msg); end

file=eo.file;

% File name should be in the 'Text' field.
[ok,msg]=checkxmlfields(file,'Text');
if ~ok, error('DBAT XML script output/files/report/file error: %s',msg); end

% Get filename.
fileName=parsepath(file.Text,baseDir);

% Verify that directory exists.
if ~exist(fileparts(fileName),'dir')
    error('DBAT XML error: Output dir %s does not exist',fileparts(fileName));
end

[fid,msg]=fopen(fileName,'wt+');
if fid<0
    error('Cannot open file %s for writing: %s',fileName,msg);
end

fprintf(fid,'# EO listing for dbat script file\n# %s.\n',docFile);
[v,d]=dbatversion;
fprintf(fid,'# Generated by DBAT version %s (%s).\n',v,d);
fprintf(fid,'# Execution UUID: %s.\n',s.proj.UUID);
fprintf(fid,['# Format: EO number, EO id, x, y, z, omega, phi, kappa, sx, sy, ' ...
             'sz, so, sk, label. Unit: degrees.\n']);

if isempty(s.post.std.EO)
    CEO=bundle_cov(s,s.bundle.info,'CEO');
    EOstd=sqrt(reshape(full(diag(CEO)),6,[]));
else
    EOstd=s.post.std.EO;
end

% For each camera
fmt=[repmat('%d, ',1,2),repmat('%.18g, ',1,12),'%s\n'];
for i=1:size(s.EO.val,2)
    fprintf(fid,fmt,i,s.EO.id(i),s.EO.val(:,i),EOstd(:,i)*180/pi,s.EO.label{i});
end
fclose(fid);

fprintf('EO output file %s generated.\n',fileName);

